package com.ahdms.es.util;

import java.util.Hashtable;

import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;

import com.ahdms.es.bean.LdapServerInfo;
import org.bouncycastle.asn1.x509.Certificate;
import org.bouncycastle.asn1.x509.CertificateList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LdapQuery {
    private static final String CERT_ATTR = "userCertificate;binary";
    private static final String CA_CERT_ATTR = "cACertificate;binary";
    private static final String CRL_ATTR = "certificateRevocationList;binary";
    private static final String CONTEXT_FACTORY = "com.sun.jndi.ldap.LdapCtxFactory";

    private static final Logger logger = LoggerFactory.getLogger(LdapQuery.class);
    
    /**
     * 连接ldap服务器
     *
     * @return
     */
    public static DirContext buildDirContext(LdapServerInfo ldapServer) throws NullPointerException {

        Hashtable<Object,Object> ht = new Hashtable<Object,Object>();
        ht.put(Context.INITIAL_CONTEXT_FACTORY, CONTEXT_FACTORY);
        ht.put(Context.PROVIDER_URL, ldapServer.getAddress());

        DirContext dc = null;
        try {
            dc = new InitialDirContext(ht);
            //add error code
        } catch (javax.naming.AuthenticationException ex) {
        	logger.error(ex.getMessage(), ex);
            //add error code
            return null;
        } catch (Exception e) {
        	logger.error(e.getMessage(), e);
            //add error code
            return null;
        }
        return dc;
    }


    /**
     * 从ldap服务器查找证书
     *
     * @param dc
     * @param ldapBean
     * @param attr
     * @return
     */
    private static Object getCertFormLdap(DirContext dc, LdapServerInfo ldapServer, String attr) {
        SearchControls ctrl = new SearchControls();
        ctrl.setSearchScope(SearchControls.SUBTREE_SCOPE);

        try {
            NamingEnumeration<SearchResult> enu = dc.search(ldapServer.getSearchDn(), ldapServer.getFilter(), ctrl);
            while (enu.hasMore()) {
                SearchResult sr = (SearchResult) enu.next();
                Attributes attributes = sr.getAttributes();
                if (attributes != null) {
                    Attribute attribute = attributes.get(attr);
                    if (attribute != null) {
                        return attribute.get();
                    }
                }
            }
        } catch (NamingException e) {
        	logger.error(e.getMessage(), e);
        }
        return null;
    }

    /**
     * 标识下载
     *
     * @param ldapBean
     * @throws NamingException
     */
    public static Certificate certDownload(LdapServerInfo ldapServer) {
        DirContext dc = buildDirContext(ldapServer);
        if (dc == null)
            return null;
        Object object = getCertFormLdap(dc, ldapServer, CERT_ATTR);
        closeDirContext(dc);
        if (object != null)
            return Certificate.getInstance(object);
        return null;
    }

    /**
     * 根证书下载
     */
    public static Certificate cACertDownload(LdapServerInfo ldapServer) {
        DirContext dc = buildDirContext(ldapServer);
        if (dc == null)
            return null;

        Object object = getCertFormLdap(dc, ldapServer, CA_CERT_ATTR);
        closeDirContext(dc);
        if (object != null)
            return Certificate.getInstance(object);
        return null;
    }

    /**
     * CRL下载
     */
    public static CertificateList CRLDownload(LdapServerInfo ldapServer) {
        DirContext dc = buildDirContext(ldapServer);
        if (dc == null)
            return null;

        Object object = getCertFormLdap(dc, ldapServer, CRL_ATTR);
        closeDirContext(dc);
        if (object != null)
            return CertificateList.getInstance(object);
        return null;
    }



    /**
     * CRL下载
     * @param server
     * @param ldapBean
     * @return
     */
//    public static IRLDownloadBean CRLDownloadBean(LdapServerInfo ldapServer) {
//        IRLDownloadBean bean = new IRLDownloadBean();
//        DirContext dc = buildDirContext(ldapServer);
//        if (dc == null) {
//            return bean;
//        }
//
//        if (!irlExists(dc, ldapBean.getDn())) {
//            // if IRL dn not exists return;
//            closeDirContext(dc);
//            return bean;
//        }
//
//        bean.setError(0);
//        Object object = getCertFormLdap(dc, ldapBean, CRL_ATTR);
//        if (object != null) {
//            bean.setIRLObject(object);
//        }
//        closeDirContext(dc);
//        return bean;
//    }

    /**
     * search irl dn exists?
     * @param dc
     * @param irlDn
     * @return
     */
    private static boolean irlExists(DirContext dc, String irlDn) {
        String filter = "(objectclass=pkiCA)";
        SearchControls controls = new SearchControls();
        controls.setSearchScope(SearchControls.OBJECT_SCOPE);

        NamingEnumeration<SearchResult> results = null;
        try {
            results = dc.search(irlDn, filter, controls);
        } catch (NamingException e) {
        	logger.error(e.getMessage(), e);
        }

        try {
            if (results != null && results.hasMore())
                return true;

        } catch (NamingException e) {
        	logger.error(e.getMessage(), e);
        }
        return false;
    }

    /**
     * close DirContext connect
     * @param dc
     */
    private static void closeDirContext(DirContext dc) {
        if (dc == null)
            return;
        try {
            dc.close();
        } catch (NamingException e) {
        	logger.error(e.getMessage(), e);
        }
    }


}

